#pragma once
#include <iostream>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <sys/socket.h>
#include <cstdlib>
#include <unistd.h>
#include <sys/types.h>
#include <sys/wait.h>
#include <signal.h>
#include <pthread.h>

#include "log.hpp"
#include "ThreadPool.hpp"
#include "Task.hpp"

enum
{
    SOCKET_ERR = 1,
    BIND_ERR,
    LISTEN_ERR,
    ACCETP_ERR,
    USAGE_ERR
};

static const uint16_t gport = 8080;
static const int gbacklog = 5;

//这份代码有一个问题，客户端退出的时候会导致服务器端也退出
class TcpServer
{
public:
    TcpServer(const uint16_t &port = gport)
        : _port(port), _listensocket(-1) {}

    void initServer()
    {
        // 创建tcp套接字
        _listensocket = socket(AF_INET, SOCK_STREAM, 0);
        if (_listensocket < 0)
        {
            logMessage(FATAL, "create socket error");
            exit(SOCKET_ERR);
        }
        logMessage(NORMAL, "create socket success");

        // 设置ip和port
        struct sockaddr_in server;
        server.sin_family = AF_INET;
        server.sin_port = htons(_port);
        server.sin_addr.s_addr = INADDR_ANY;

        // 绑定socket和本地地址
        if (bind(_listensocket, (struct sockaddr *)&server, sizeof(server)) < 0)
        {
            logMessage(FATAL, "bind socket error");
            exit(BIND_ERR);
        }
        logMessage(NORMAL, "bind socket success");

        // 由于tcp是面向连接的，所以在绑定之后还要对socket进行监听，来获取连接
        if (listen(_listensocket, gbacklog) < 0)
        {
            logMessage(FATAL, "listen socket error");
            exit(LISTEN_ERR);
        }
        logMessage(NORMAL, "listen socket success");
    }

    void start()
    {
        // 线程池版
        ThreadPool<Task> *tp = new ThreadPool<Task>();
        tp->run();
        while (true)
        {
            struct sockaddr_in peer;
            socklen_t len = sizeof(peer);
            // accept调用成功后会返回一个新的套接字描述符，后续和客户端的交流都是通过这个新的描述符
            int socket = accept(_listensocket, (struct sockaddr *)&peer, &len);
            if (socket < 0)
            {
                logMessage(FATAL, "accept socket error");
                continue;
            }
            logMessage(NORMAL, "accept socket success");

            tp->push(Task(socket, serverIO));
        }
    }

    ~TcpServer()
    {
    }

private:
    uint16_t _port;
    int _listensocket; // 这个套接字描述符只是用来获取连接
};